#include "Perceptron_cmd.h"

#define DEFAULT_INPUT 5
#define DEFAULT_LAYER1 4
#define DEFAULT_LAYER2 3
#define DEFAULT_GAIN 0.5f

#define INI_FILENAME ".\\perceptron.ini"
#define INI_SETTING "Setting"
#define WEIGHTS_SAVE_FILE "perceptron_weights"

void InitPerceptron(){
	char str[40];

	CIniReader iniReader(INI_FILENAME);
	int inputSize = iniReader.ReadInteger(INI_SETTING, "Input", DEFAULT_INPUT);
	int n1 = iniReader.ReadInteger(INI_SETTING, "Layer1", DEFAULT_LAYER1);
	int n2 = iniReader.ReadInteger(INI_SETTING, "Layer2", DEFAULT_LAYER2);
	double gain = iniReader.ReadFloat(INI_SETTING, "Gain", DEFAULT_GAIN);

	::InputSize = inputSize;
	
	PObj = Perceptron(inputSize, n1, n2, gain);

	ifstream ifs(WEIGHTS_SAVE_FILE);
	if(ifs.is_open()){
		int begin = 1 + PObj.layerSizes[0];
		for(int l=1; l<PObj.layerLength; l++){
			for(int j=0; j<PObj.layerSizes[l]; j++){
				if(ifs.good()){
					ifs.getline(str, 40);
					PObj.weights[begin+j][0] = atof(str);
				}
				for(int i=0; i<PObj.layerSizes[l-1]; i++){
					if(ifs.good()){
						ifs.getline(str, 40);
						PObj.weights[begin+j][begin-1-i] = atof(str);
					}
				}
			}
			begin += PObj.layerSizes[l];
		}
	}

	ifs.close();
}

void SavePerceptron(){
	CIniWriter iniWriter(INI_FILENAME);
	iniWriter.WriteInteger(INI_SETTING, "Input", PObj.layerSizes[0]);
	iniWriter.WriteInteger(INI_SETTING, "Layer1", PObj.layerSizes[1]);
	iniWriter.WriteInteger(INI_SETTING, "Layer2", PObj.layerSizes[2]);
	iniWriter.WriteFloat(INI_SETTING, "Gain", PObj.stress);

	ofstream ofs(WEIGHTS_SAVE_FILE);

	int begin = 1 + PObj.layerSizes[0];
	for(int l=1; l<PObj.layerLength; l++){
		for(int j=0; j<PObj.layerSizes[l]; j++){
			ofs << PObj.weights[begin+j][0] << endl;
			for(int i=0; i<PObj.layerSizes[l-1]; i++){
				ofs <<PObj.weights[begin+j][begin-1-i] << endl;
			}
		}
		begin += PObj.layerSizes[l];
	}

	ofs.close();
}

void ReadInputFile(char *file){
	char str[40];
	short count = 0, fcount=0;
	PData *data = new PData;

	ifstream ifs(file);
	while(ifs.good()){
		ifs.getline(str, 40);
		if(count++ == ::InputSize){
			data->result = atof(str);
			PObj.datas.push_back(*data);
			data = new PData;
			count = 0;
			continue;
		}
		data->inputs.push_back(atof(str));
		fcount++;
	}
	if(count != 0){
		delete data;
	}

#ifdef _DEBUG
	int i,j;
	for(i=0; i<PObj.datas.size(); i++){
		for(j=0; j<PObj.datas[i].inputs.size(); j++){
			cout << PObj.datas[i].inputs[j] << " ";
		}
		cout << "["<< PObj.datas[i].result <<"]" << endl;
	}
	cout << "size : " << i * j << ", " << fcount << ", " << count << endl;
#endif

	ifs.close();
}

void makeData(char *tfile, char *ofile, int length){
	PData data;

	ofstream ofs(ofile);

	ReadInputFile(tfile);
	data = PObj.datas.back();
	PObj.datas.clear();

	for(int i=0; i<length; i++){
//		PObj.datas.push_back(data);
//		double res = PObj.study();
		double res = PObj.test(data);
		ofs << res << endl;
//		PObj.datas.clear();
		data.inputs.erase(data.inputs.begin());
		data.inputs.push_back(data.result);
		data.result = res;
	}
	ofs.close();
}

void Test(char *tfile, char *ofile){
	char str[40];
	short count = 0, fcount=0;
	PData data;

	ofstream ofs(ofile);
	ifstream ifs(tfile);
	while(ifs.good()){
		ifs.getline(str, 40);
		if(count++ > ::InputSize){
			data.result = atof(str);
		//	cout << PObj.test(data) << " - " << data.result << " = " << (PObj.test(data) - data.result) << endl;
			ofs << PObj.test(data) << endl;
	//		PObj.datas.push_back(data);
//			data.inputs.clear();
			data.inputs.erase(data.inputs.begin());
		//	continue;
		}
		data.inputs.push_back(atof(str));
		fcount++;
	}

	ifs.close();
	ofs.close();
}

int main(int argc, char *argv[]){
	if(argc < 2){
		cout << "Using : Perceptron [train.txt]" << endl;
		cout << "        Perceptron [test.txt] [output.txt]" << endl;
	}

	InitPerceptron();
	if(argc == 3){
		Test(argv[1], argv[2]);
		return 0;
	}
	ReadInputFile(argv[1]);
	cout << "now training.. waiting ...." << endl;
	PObj.study();
/*
	if(argc == 4){
		makeData(argv[1], argv[2], atoi(argv[3]));
	}
*/
	SavePerceptron();

	return 0;
}